1   /*                        __    __  __  __    __  ___
2    *                       \  \  /  /    \  \  /  /  __/
3    *                        \  \/  /  /\  \  \/  /  /
4    *                         \____/__/  \__\____/__/.ɪᴏ
5    * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
6    */
7   package io.vavr.collection;
8   
9   import io.vavr.*;
10  import io.vavr.collection.ArrayModule.Combinations;
11  import io.vavr.control.Option;
12  
13  import java.io.Serializable;
14  import java.util.*;
15  import java.util.function.*;
16  import java.util.stream.Collector;
17  
18  import static io.vavr.collection.JavaConverters.ChangePolicy.IMMUTABLE;
19  import static io.vavr.collection.JavaConverters.ChangePolicy.MUTABLE;
20  import static java.util.Arrays.copyOf;
21  import static java.util.Arrays.sort;
22  
23  /**
24   * Array is a Traversable wrapper for {@code Object[]} containing elements of type {@code T}.
25   *
26   * @param <T> Component type
27   * @author Ruslan Sennov, Daniel Dietrich
28   */
29  public final class Array<T> implements IndexedSeq<T>, Serializable {
30      private static final long serialVersionUID = 1L;
31  
32      private static final Array<?> EMPTY = new Array<>(new Object[0]);
33  
34      private final Object[] delegate;
35  
36      private Array(Object[] delegate) {
37          this.delegate = delegate;
38      }
39  
40      static <T> Array<T> wrap(Object[] array) {
41          return (array.length == 0) ? empty() : new Array<>(array);
42      }
43  
44      /**
45       * Returns a {@link java.util.stream.Collector} which may be used in conjunction with
46       * {@link java.util.stream.Stream#collect(java.util.stream.Collector)} to obtain a {@link Array}.
47       *
48       * @param <T> Component type of the Array.
49       * @return A {@link Array} Collector.
50       */
51      public static <T> Collector<T, ArrayList<T>, Array<T>> collector() {
52          final Supplier<ArrayList<T>> supplier = ArrayList::new;
53          final BiConsumer<ArrayList<T>, T> accumulator = ArrayList::add;
54          final BinaryOperator<ArrayList<T>> combiner = (left, right) -> {
55              left.addAll(right);
56              return left;
57          };
58          final Function<ArrayList<T>, Array<T>> finisher = Array::ofAll;
59          return Collector.of(supplier, accumulator, combiner, finisher);
60      }
61  
62      @SuppressWarnings("unchecked")
63      public static <T> Array<T> empty() {
64          return (Array<T>) EMPTY;
65      }
66  
67      /**
68       * Narrows a widened {@code Array<? extends T>} to {@code Array<T>}
69       * by performing a type-safe cast. This is eligible because immutable/read-only
70       * collections are covariant.
71       *
72       * @param array An {@code Array}.
73       * @param <T>   Component type of the {@code Array}.
74       * @return the given {@code array} instance as narrowed type {@code Array<T>}.
75       */
76      @SuppressWarnings("unchecked")
77      public static <T> Array<T> narrow(Array<? extends T> array) {
78          return (Array<T>) array;
79      }
80  
81      /**
82       * Returns a singleton {@code Array}, i.e. a {@code Array} of one element.
83       *
84       * @param element An element.
85       * @param <T>     The component type
86       * @return A new Array instance containing the given element
87       */
88      public static <T> Array<T> of(T element) {
89          return wrap(new Object[] { element });
90      }
91  
92      /**
93       * Creates an Array of the given elements.
94       *
95       * @param <T>      Component type of the Array.
96       * @param elements Zero or more elements.
97       * @return An Array containing the given elements in the same order.
98       * @throws NullPointerException if {@code elements} is null
99       */
100     @SuppressWarnings("varargs")
101     @SafeVarargs
102     public static <T> Array<T> of(T... elements) {
103         Objects.requireNonNull(elements, "elements is null");
104         return wrap(copyOf(elements, elements.length));
105     }
106 
107     /**
108      * Creates an Array of the given elements.
109      * <p>
110      * The resulting Array has the same iteration order as the given iterable of elements
111      * if the iteration order of the elements is stable.
112      *
113      * @param <T>      Component type of the Array.
114      * @param elements An Iterable of elements.
115      * @return An Array containing the given elements in the same order.
116      * @throws NullPointerException if {@code elements} is null
117      */
118     @SuppressWarnings("unchecked")
119     public static <T> Array<T> ofAll(Iterable<? extends T> elements) {
120         Objects.requireNonNull(elements, "elements is null");
121         return elements instanceof Array
122                ? (Array<T>) elements
123                : wrap(toArray(elements));
124     }
125 
126     /**
127      * Creates an Array that contains the elements of the given {@link java.util.stream.Stream}.
128      *
129      * @param javaStream A {@link java.util.stream.Stream}
130      * @param <T>        Component type of the Stream.
131      * @return An Array containing the given elements in the same order.
132      */
133     public static <T> Array<T> ofAll(java.util.stream.Stream<? extends T> javaStream) {
134         Objects.requireNonNull(javaStream, "javaStream is null");
135         return wrap(javaStream.toArray());
136     }
137 
138     /**
139      * Creates an Array from boolean values.
140      *
141      * @param elements boolean values
142      * @return A new Array of Boolean values
143      * @throws NullPointerException if elements is null
144      */
145     public static Array<Boolean> ofAll(boolean... elements) {
146         Objects.requireNonNull(elements, "elements is null");
147         return ofAll(Iterator.ofAll(elements));
148     }
149 
150     /**
151      * Creates an Array from byte values.
152      *
153      * @param elements byte values
154      * @return A new Array of Byte values
155      * @throws NullPointerException if elements is null
156      */
157     public static Array<Byte> ofAll(byte... elements) {
158         Objects.requireNonNull(elements, "elements is null");
159         return ofAll(Iterator.ofAll(elements));
160     }
161 
162     /**
163      * Creates an Array from char values.
164      *
165      * @param elements char values
166      * @return A new Array of Character values
167      * @throws NullPointerException if elements is null
168      */
169     public static Array<Character> ofAll(char... elements) {
170         Objects.requireNonNull(elements, "elements is null");
171         return ofAll(Iterator.ofAll(elements));
172     }
173 
174     /**
175      * Creates an Array from double values.
176      *
177      * @param elements double values
178      * @return A new Array of Double values
179      * @throws NullPointerException if elements is null
180      */
181     public static Array<Double> ofAll(double... elements) {
182         Objects.requireNonNull(elements, "elements is null");
183         return ofAll(Iterator.ofAll(elements));
184     }
185 
186     /**
187      * Creates an Array from float values.
188      *
189      * @param elements float values
190      * @return A new Array of Float values
191      * @throws NullPointerException if elements is null
192      */
193     public static Array<Float> ofAll(float... elements) {
194         Objects.requireNonNull(elements, "elements is null");
195         return ofAll(Iterator.ofAll(elements));
196     }
197 
198     /**
199      * Creates an Array from int values.
200      *
201      * @param elements int values
202      * @return A new Array of Integer values
203      * @throws NullPointerException if elements is null
204      */
205     public static Array<Integer> ofAll(int... elements) {
206         Objects.requireNonNull(elements, "elements is null");
207         return ofAll(Iterator.ofAll(elements));
208     }
209 
210     /**
211      * Creates an Array from long values.
212      *
213      * @param elements long values
214      * @return A new Array of Long values
215      * @throws NullPointerException if elements is null
216      */
217     public static Array<Long> ofAll(long... elements) {
218         Objects.requireNonNull(elements, "elements is null");
219         return ofAll(Iterator.ofAll(elements));
220     }
221 
222     /**
223      * Creates an Array from short values.
224      *
225      * @param elements short values
226      * @return A new Array of Short values
227      * @throws NullPointerException if elements is null
228      */
229     public static Array<Short> ofAll(short... elements) {
230         Objects.requireNonNull(elements, "elements is null");
231         return ofAll(Iterator.ofAll(elements));
232     }
233 
234     /**
235      * Returns an Array containing {@code n} values of a given Function {@code f}
236      * over a range of integer values from 0 to {@code n - 1}.
237      *
238      * @param <T> Component type of the Array
239      * @param n   The number of elements in the Array
240      * @param f   The Function computing element values
241      * @return An Array consisting of elements {@code f(0),f(1), ..., f(n - 1)}
242      * @throws NullPointerException if {@code f} is null
243      */
244     public static <T> Array<T> tabulate(int n, Function<? super Integer, ? extends T> f) {
245         Objects.requireNonNull(f, "f is null");
246         return io.vavr.collection.Collections.tabulate(n, f, empty(), Array::of);
247     }
248 
249     /**
250      * Returns an Array containing {@code n} values supplied by a given Supplier {@code s}.
251      *
252      * @param <T> Component type of the Array
253      * @param n   The number of elements in the Array
254      * @param s   The Supplier computing element values
255      * @return An Array of size {@code n}, where each element contains the result supplied by {@code s}.
256      * @throws NullPointerException if {@code s} is null
257      */
258     public static <T> Array<T> fill(int n, Supplier<? extends T> s) {
259         Objects.requireNonNull(s, "s is null");
260         return io.vavr.collection.Collections.fill(n, s, empty(), Array::of);
261     }
262 
263     public static Array<Character> range(char from, char toExclusive) {
264         return ofAll(Iterator.range(from, toExclusive));
265     }
266 
267     public static Array<Character> rangeBy(char from, char toExclusive, int step) {
268         return ofAll(Iterator.rangeBy(from, toExclusive, step));
269     }
270 
271     @GwtIncompatible
272     public static Array<Double> rangeBy(double from, double toExclusive, double step) {
273         return ofAll(Iterator.rangeBy(from, toExclusive, step));
274     }
275 
276     /**
277      * Creates an Array of int numbers starting from {@code from}, extending to {@code toExclusive - 1}.
278      * <p>
279      * Examples:
280      * <pre>
281      * <code>
282      * Array.range(0, 0)  // = Array()
283      * Array.range(2, 0)  // = Array()
284      * Array.range(-2, 2) // = Array(-2, -1, 0, 1)
285      * </code>
286      * </pre>
287      *
288      * @param from        the first number
289      * @param toExclusive the last number + 1
290      * @return a range of int values as specified or the empty range if {@code from >= toExclusive}
291      */
292     public static Array<Integer> range(int from, int toExclusive) {
293         return ofAll(Iterator.range(from, toExclusive));
294     }
295 
296     /**
297      * Creates an Array of int numbers starting from {@code from}, extending to {@code toExclusive - 1},
298      * with {@code step}.
299      * <p>
300      * Examples:
301      * <pre>
302      * <code>
303      * Array.rangeBy(1, 3, 1)  // = Array(1, 2)
304      * Array.rangeBy(1, 4, 2)  // = Array(1, 3)
305      * Array.rangeBy(4, 1, -2) // = Array(4, 2)
306      * Array.rangeBy(4, 1, 2)  // = Array()
307      * </code>
308      * </pre>
309      *
310      * @param from        the first number
311      * @param toExclusive the last number + 1
312      * @param step        the step
313      * @return a range of long values as specified or the empty range if<br>
314      * {@code from >= toInclusive} and {@code step > 0} or<br>
315      * {@code from <= toInclusive} and {@code step < 0}
316      * @throws IllegalArgumentException if {@code step} is zero
317      */
318     public static Array<Integer> rangeBy(int from, int toExclusive, int step) {
319         return ofAll(Iterator.rangeBy(from, toExclusive, step));
320     }
321 
322     /**
323      * Creates an Array of long numbers starting from {@code from}, extending to {@code toExclusive - 1}.
324      * <p>
325      * Examples:
326      * <pre>
327      * <code>
328      * Array.range(0L, 0L)  // = Array()
329      * Array.range(2L, 0L)  // = Array()
330      * Array.range(-2L, 2L) // = Array(-2L, -1L, 0L, 1L)
331      * </code>
332      * </pre>
333      *
334      * @param from        the first number
335      * @param toExclusive the last number + 1
336      * @return a range of long values as specified or the empty range if {@code from >= toExclusive}
337      */
338     public static Array<Long> range(long from, long toExclusive) {
339         return ofAll(Iterator.range(from, toExclusive));
340     }
341 
342     /**
343      * Creates an Array of long numbers starting from {@code from}, extending to {@code toExclusive - 1},
344      * with {@code step}.
345      * <p>
346      * Examples:
347      * <pre>
348      * <code>
349      * Array.rangeBy(1L, 3L, 1L)  // = Array(1L, 2L)
350      * Array.rangeBy(1L, 4L, 2L)  // = Array(1L, 3L)
351      * Array.rangeBy(4L, 1L, -2L) // = Array(4L, 2L)
352      * Array.rangeBy(4L, 1L, 2L)  // = Array()
353      * </code>
354      * </pre>
355      *
356      * @param from        the first number
357      * @param toExclusive the last number + 1
358      * @param step        the step
359      * @return a range of long values as specified or the empty range if<br>
360      * {@code from >= toInclusive} and {@code step > 0} or<br>
361      * {@code from <= toInclusive} and {@code step < 0}
362      * @throws IllegalArgumentException if {@code step} is zero
363      */
364     public static Array<Long> rangeBy(long from, long toExclusive, long step) {
365         return ofAll(Iterator.rangeBy(from, toExclusive, step));
366     }
367 
368     public static Array<Character> rangeClosed(char from, char toInclusive) {
369         return ofAll(Iterator.rangeClosed(from, toInclusive));
370     }
371 
372     public static Array<Character> rangeClosedBy(char from, char toInclusive, int step) {
373         return ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
374     }
375 
376     @GwtIncompatible
377     public static Array<Double> rangeClosedBy(double from, double toInclusive, double step) {
378         return ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
379     }
380 
381     /**
382      * Creates an Array of int numbers starting from {@code from}, extending to {@code toInclusive}.
383      * <p>
384      * Examples:
385      * <pre>
386      * <code>
387      * Array.rangeClosed(0, 0)  // = Array(0)
388      * Array.rangeClosed(2, 0)  // = Array()
389      * Array.rangeClosed(-2, 2) // = Array(-2, -1, 0, 1, 2)
390      * </code>
391      * </pre>
392      *
393      * @param from        the first number
394      * @param toInclusive the last number
395      * @return a range of int values as specified or the empty range if {@code from > toInclusive}
396      */
397     public static Array<Integer> rangeClosed(int from, int toInclusive) {
398         return ofAll(Iterator.rangeClosed(from, toInclusive));
399     }
400 
401     /**
402      * Creates an Array of int numbers starting from {@code from}, extending to {@code toInclusive},
403      * with {@code step}.
404      * <p>
405      * Examples:
406      * <pre>
407      * <code>
408      * Array.rangeClosedBy(1, 3, 1)  // = Array(1, 2, 3)
409      * Array.rangeClosedBy(1, 4, 2)  // = Array(1, 3)
410      * Array.rangeClosedBy(4, 1, -2) // = Array(4, 2)
411      * Array.rangeClosedBy(4, 1, 2)  // = Array()
412      * </code>
413      * </pre>
414      *
415      * @param from        the first number
416      * @param toInclusive the last number
417      * @param step        the step
418      * @return a range of int values as specified or the empty range if<br>
419      * {@code from > toInclusive} and {@code step > 0} or<br>
420      * {@code from < toInclusive} and {@code step < 0}
421      * @throws IllegalArgumentException if {@code step} is zero
422      */
423     public static Array<Integer> rangeClosedBy(int from, int toInclusive, int step) {
424         return ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
425     }
426 
427     /**
428      * Creates an Array of long numbers starting from {@code from}, extending to {@code toInclusive}.
429      * <p>
430      * Examples:
431      * <pre>
432      * <code>
433      * Array.rangeClosed(0L, 0L)  // = Array(0L)
434      * Array.rangeClosed(2L, 0L)  // = Array()
435      * Array.rangeClosed(-2L, 2L) // = Array(-2L, -1L, 0L, 1L, 2L)
436      * </code>
437      * </pre>
438      *
439      * @param from        the first number
440      * @param toInclusive the last number
441      * @return a range of long values as specified or the empty range if {@code from > toInclusive}
442      */
443     public static Array<Long> rangeClosed(long from, long toInclusive) {
444         return ofAll(Iterator.rangeClosed(from, toInclusive));
445     }
446 
447     /**
448      * Creates an Array of long numbers starting from {@code from}, extending to {@code toInclusive},
449      * with {@code step}.
450      * <p>
451      * Examples:
452      * <pre>
453      * <code>
454      * Array.rangeClosedBy(1L, 3L, 1L)  // = Array(1L, 2L, 3L)
455      * Array.rangeClosedBy(1L, 4L, 2L)  // = Array(1L, 3L)
456      * Array.rangeClosedBy(4L, 1L, -2L) // = Array(4L, 2L)
457      * Array.rangeClosedBy(4L, 1L, 2L)  // = Array()
458      * </code>
459      * </pre>
460      *
461      * @param from        the first number
462      * @param toInclusive the last number
463      * @param step        the step
464      * @return a range of int values as specified or the empty range if<br>
465      * {@code from > toInclusive} and {@code step > 0} or<br>
466      * {@code from < toInclusive} and {@code step < 0}
467      * @throws IllegalArgumentException if {@code step} is zero
468      */
469     public static Array<Long> rangeClosedBy(long from, long toInclusive, long step) {
470         return ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
471     }
472 
473     /**
474      * Transposes the rows and columns of an {@link Array} matrix.
475      *
476      * @param matrix to be transposed.
477      * @return a transposed {@link Array} matrix.
478      * @throws IllegalArgumentException if the row lengths of {@code matrix} differ.
479      * <p>
480      * ex: {@code
481      * Array.transpose(Array(Array(1,2,3), Array(4,5,6))) → Array(Array(1,4), Array(2,5), Array(3,6))
482      * }
483      */
484     static <T> Array<Array<T>> transpose(Array<Array<T>> matrix) {
485         return io.vavr.collection.Collections.transpose(matrix, Array::ofAll, Array::of);
486     }
487 
488     /**
489      * Creates an Array from a seed value and a function.
490      * The function takes the seed at first.
491      * The function should return {@code None} when it's
492      * done generating the Array, otherwise {@code Some} {@code Tuple}
493      * of the element for the next call and the value to add to the
494      * resulting Array.
495      * <p>
496      * Example:
497      * <pre>
498      * <code>
499      * Array.unfoldRight(10, x -&gt; x == 0
500      *             ? Option.none()
501      *             : Option.of(new Tuple2&lt;gt;(x, x-1)));
502      * // Array(10, 9, 8, 7, 6, 5, 4, 3, 2, 1))
503      * </code>
504      * </pre>
505      *
506      * @param <T>  type of seeds
507      * @param <U>  type of unfolded values
508      * @param seed the start value for the iteration
509      * @param f    the function to get the next step of the iteration
510      * @return an Array with the values built up by the iteration
511      * @throws NullPointerException if {@code f} is null
512      */
513     public static <T, U> Array<U> unfoldRight(T seed, Function<? super T, Option<Tuple2<? extends U, ? extends T>>> f) {
514         return Iterator.unfoldRight(seed, f).toArray();
515     }
516 
517     /**
518      * Creates an Array from a seed value and a function.
519      * The function takes the seed at first.
520      * The function should return {@code None} when it's
521      * done generating the list, otherwise {@code Some} {@code Tuple}
522      * of the value to add to the resulting list and
523      * the element for the next call.
524      * <p>
525      * Example:
526      * <pre>
527      * <code>
528      * Array.unfoldLeft(10, x -&gt; x == 0
529      *             ? Option.none()
530      *             : Option.of(new Tuple2&lt;gt;(x-1, x)));
531      * // Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
532      * </code>
533      * </pre>
534      *
535      * @param <T>  type of seeds
536      * @param <U>  type of unfolded values
537      * @param seed the start value for the iteration
538      * @param f    the function to get the next step of the iteration
539      * @return an Array with the values built up by the iteration
540      * @throws NullPointerException if {@code f} is null
541      */
542     public static <T, U> Array<U> unfoldLeft(T seed, Function<? super T, Option<Tuple2<? extends T, ? extends U>>> f) {
543         return Iterator.unfoldLeft(seed, f).toArray();
544     }
545 
546     /**
547      * Creates an Array from a seed value and a function.
548      * The function takes the seed at first.
549      * The function should return {@code None} when it's
550      * done generating the list, otherwise {@code Some} {@code Tuple}
551      * of the value to add to the resulting list and
552      * the element for the next call.
553      * <p>
554      * Example:
555      * <pre>
556      * <code>
557      * Array.unfold(10, x -&gt; x == 0
558      *             ? Option.none()
559      *             : Option.of(new Tuple2&lt;gt;(x-1, x)));
560      * // Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
561      * </code>
562      * </pre>
563      *
564      * @param <T>  type of seeds and unfolded values
565      * @param seed the start value for the iteration
566      * @param f    the function to get the next step of the iteration
567      * @return an Array with the values built up by the iteration
568      * @throws NullPointerException if {@code f} is null
569      */
570     public static <T> Array<T> unfold(T seed, Function<? super T, Option<Tuple2<? extends T, ? extends T>>> f) {
571         return Iterator.unfold(seed, f).toArray();
572     }
573 
574     @Override
575     public Array<T> append(T element) {
576         final Object[] copy = copyOf(delegate, delegate.length + 1);
577         copy[delegate.length] = element;
578         return wrap(copy);
579     }
580 
581     @Override
582     public Array<T> appendAll(Iterable<? extends T> elements) {
583         Objects.requireNonNull(elements, "elements is null");
584         if (isEmpty() && elements instanceof Array) {
585             @SuppressWarnings("unchecked")
586             final Array<T> array = (Array<T>) elements;
587             return array;
588         }
589         final Object[] source = toArray(elements);
590         if (source.length == 0) {
591             return this;
592         } else {
593             final Object[] arr = copyOf(delegate, delegate.length + source.length);
594             System.arraycopy(source, 0, arr, delegate.length, source.length);
595             return wrap(arr);
596         }
597     }
598     
599     @Override
600     public java.util.List<T> asJava() {
601         return JavaConverters.asJava(this, IMMUTABLE);
602     }
603 
604     @Override
605     public Array<T> asJava(Consumer<? super java.util.List<T>> action) {
606         return Collections.asJava(this, action, IMMUTABLE);
607     }
608 
609     @Override
610     public java.util.List<T> asJavaMutable() {
611         return JavaConverters.asJava(this, MUTABLE);
612     }
613 
614     @Override
615     public Array<T> asJavaMutable(Consumer<? super java.util.List<T>> action) {
616         return Collections.asJava(this, action, MUTABLE);
617     }
618 
619     @Override
620     public <R> Array<R> collect(PartialFunction<? super T, ? extends R> partialFunction) {
621         return ofAll(iterator().<R> collect(partialFunction));
622     }
623     
624     @Override
625     public boolean hasDefiniteSize() {
626         return true;
627     }
628 
629     /**
630      * An {@code Array} is computed synchronously.
631      *
632      * @return false
633      */
634     @Override
635     public boolean isAsync() {
636         return false;
637     }
638 
639     /**
640      * An {@code Array} is computed eagerly.
641      *
642      * @return false
643      */
644     @Override
645     public boolean isLazy() {
646         return false;
647     }
648 
649     @Override
650     public boolean isTraversableAgain() {
651         return true;
652     }
653 
654     @SuppressWarnings("unchecked")
655     @Override
656     public Iterator<T> iterator() {
657         return new AbstractIterator<T>() {
658             private int index = 0;
659 
660             @Override
661             public boolean hasNext() {
662                 return index < delegate.length;
663             }
664 
665             @Override
666             public T getNext() {
667                 return (T) delegate[index++];
668             }
669         };
670     }
671 
672     @Override
673     public Array<Array<T>> combinations() {
674         return rangeClosed(0, length()).map(this::combinations).flatMap(Function.identity());
675     }
676 
677     @Override
678     public Array<Array<T>> combinations(int k) {
679         return Combinations.apply(this, Math.max(k, 0));
680     }
681 
682     @Override
683     public Iterator<Array<T>> crossProduct(int power) {
684         return io.vavr.collection.Collections.crossProduct(empty(), this, power);
685     }
686 
687     @SuppressWarnings("unchecked")
688     @Override
689     public T get(int index) {
690         if (index < 0 || index >= length()) {
691             throw new IndexOutOfBoundsException("get(" + index + ")");
692         }
693         return (T) delegate[index];
694     }
695 
696     @Override
697     public Array<T> distinct() {
698         return distinctBy(Function.identity());
699     }
700 
701     @Override
702     public Array<T> distinctBy(Comparator<? super T> comparator) {
703         Objects.requireNonNull(comparator, "comparator is null");
704         final java.util.Set<T> seen = new java.util.TreeSet<>(comparator);
705         return filter(seen::add);
706     }
707 
708     @Override
709     public <U> Array<T> distinctBy(Function<? super T, ? extends U> keyExtractor) {
710         Objects.requireNonNull(keyExtractor, "keyExtractor is null");
711         final java.util.Set<U> seen = new java.util.HashSet<>();
712         return filter(t -> seen.add(keyExtractor.apply(t)));
713     }
714 
715     @Override
716     public Array<T> drop(int n) {
717         if (n <= 0) {
718             return this;
719         } else if (n >= length()) {
720             return empty();
721         } else {
722             final Object[] arr = new Object[delegate.length - n];
723             System.arraycopy(delegate, n, arr, 0, arr.length);
724             return wrap(arr);
725         }
726     }
727 
728     @Override
729     public Array<T> dropUntil(Predicate<? super T> predicate) {
730         return io.vavr.collection.Collections.dropUntil(this, predicate);
731     }
732 
733     @Override
734     public Array<T> dropWhile(Predicate<? super T> predicate) {
735         Objects.requireNonNull(predicate, "predicate is null");
736         return dropUntil(predicate.negate());
737     }
738 
739     @Override
740     public Array<T> dropRight(int n) {
741         if (n <= 0) {
742             return this;
743         } else if (n >= length()) {
744             return empty();
745         } else {
746             return wrap(copyOf(delegate, delegate.length - n));
747         }
748     }
749 
750     @Override
751     public Array<T> dropRightUntil(Predicate<? super T> predicate) {
752         return io.vavr.collection.Collections.dropRightUntil(this, predicate);
753     }
754 
755     @Override
756     public Array<T> dropRightWhile(Predicate<? super T> predicate) {
757         Objects.requireNonNull(predicate, "predicate is null");
758         return dropRightUntil(predicate.negate());
759     }
760 
761     @Override
762     public Array<T> filter(Predicate<? super T> predicate) {
763         Objects.requireNonNull(predicate, "predicate is null");
764         final java.util.List<T> list = new ArrayList<>();
765         for (T t : this) {
766             if (predicate.test(t)) {
767                 list.add(t);
768             }
769         }
770         if (list.isEmpty()) {
771             return empty();
772         } else if (list.size() == size()) {
773             return this;
774         } else {
775             return wrap(list.toArray());
776         }
777     }
778 
779     @Override
780     public <U> Array<U> flatMap(Function<? super T, ? extends Iterable<? extends U>> mapper) {
781         Objects.requireNonNull(mapper, "mapper is null");
782         if (isEmpty()) {
783             return empty();
784         } else {
785             final java.util.List<U> list = new ArrayList<>();
786             for (T t : this) {
787                 for (U u : mapper.apply(t)) {
788                     list.add(u);
789                 }
790             }
791             return wrap(list.toArray());
792         }
793     }
794 
795     @Override
796     public <C> Map<C, Array<T>> groupBy(Function<? super T, ? extends C> classifier) {
797         return io.vavr.collection.Collections.groupBy(this, classifier, Array::ofAll);
798     }
799 
800     @Override
801     public Iterator<Array<T>> grouped(int size) {
802         return sliding(size, size);
803     }
804 
805     @SuppressWarnings("unchecked")
806     @Override
807     public T head() {
808         if (isEmpty()) {
809             throw new NoSuchElementException("head on empty Array");
810         } else {
811             return (T) delegate[0];
812         }
813     }
814 
815     @Override
816     public int indexOf(T element, int from) {
817         for (int i = from; i < length(); i++) {
818             if (Objects.equals(get(i), element)) {
819                 return i;
820             }
821         }
822         return -1;
823     }
824 
825     @Override
826     public Array<T> init() {
827         if (isEmpty()) {
828             throw new UnsupportedOperationException("init of empty Array");
829         }
830         return dropRight(1);
831     }
832 
833     @Override
834     public Option<Array<T>> initOption() {
835         return isEmpty() ? Option.none() : Option.some(init());
836     }
837 
838     @Override
839     public boolean isEmpty() {
840         return delegate.length == 0;
841     }
842 
843     private Object readResolve() {
844         return isEmpty() ? EMPTY : this;
845     }
846 
847     @Override
848     public Array<T> insert(int index, T element) {
849         if (index < 0 || index > length()) {
850             throw new IndexOutOfBoundsException("insert(" + index + ", e) on Array of length " + length());
851         }
852         final Object[] arr = new Object[delegate.length + 1];
853         System.arraycopy(delegate, 0, arr, 0, index);
854         arr[index] = element;
855         System.arraycopy(delegate, index, arr, index + 1, delegate.length - index);
856         return wrap(arr);
857     }
858 
859     @Override
860     public Array<T> insertAll(int index, Iterable<? extends T> elements) {
861         if (index < 0 || index > length()) {
862             throw new IndexOutOfBoundsException("insert(" + index + ", e) on Array of length " + length());
863         }
864         if (isEmpty() && elements instanceof Array) {
865             @SuppressWarnings("unchecked")
866             final Array<T> array = (Array<T>) elements;
867             return array;
868         }
869         final Object[] list = toArray(elements);
870         if (list.length == 0) {
871             return this;
872         } else {
873             final Object[] arr = new Object[delegate.length + list.length];
874             System.arraycopy(delegate, 0, arr, 0, index);
875             System.arraycopy(list, 0, arr, index, list.length);
876             System.arraycopy(delegate, index, arr, index + list.length, delegate.length - index);
877             return wrap(arr);
878         }
879     }
880 
881     @Override
882     public Array<T> intersperse(T element) {
883         if (delegate.length <= 1) {
884             return this;
885         } else {
886             final Object[] arr = new Object[delegate.length * 2 - 1];
887             for (int i = 0; i < delegate.length; i++) {
888                 arr[i * 2] = delegate[i];
889                 if (i > 0) {
890                     arr[i * 2 - 1] = element;
891                 }
892             }
893             return wrap(arr);
894         }
895     }
896 
897     @Override
898     public int lastIndexOf(T element, int end) {
899         for (int i = Math.min(end, length() - 1); i >= 0; i--) {
900             if (Objects.equals(get(i), element)) {
901                 return i;
902             }
903         }
904         return -1;
905     }
906 
907     @Override
908     public int length() {
909         return delegate.length;
910     }
911 
912     @Override
913     public <U> Array<U> map(Function<? super T, ? extends U> mapper) {
914         Objects.requireNonNull(mapper, "mapper is null");
915         final Object[] arr = new Object[length()];
916         for (int i = 0; i < delegate.length; i++) {
917             arr[i] = mapper.apply(get(i));
918         }
919         return wrap(arr);
920     }
921 
922     @Override
923     public Array<T> orElse(Iterable<? extends T> other) {
924         return isEmpty() ? ofAll(other) : this;
925     }
926 
927     @Override
928     public Array<T> orElse(Supplier<? extends Iterable<? extends T>> supplier) {
929         return isEmpty() ? ofAll(supplier.get()) : this;
930     }
931 
932     @Override
933     public Array<T> padTo(int length, T element) {
934         final int actualLength = length();
935         if (length <= actualLength) {
936             return this;
937         } else {
938             return appendAll(Iterator.continually(element).take(length - actualLength));
939         }
940     }
941 
942     @Override
943     public Array<T> leftPadTo(int length, T element) {
944         final int actualLength = length();
945         if (length <= actualLength) {
946             return this;
947         } else {
948             return prependAll(Iterator.continually(element).take(length - actualLength));
949         }
950     }
951 
952     @Override
953     public Array<T> patch(int from, Iterable<? extends T> that, int replaced) {
954         from = from < 0 ? 0 : from;
955         replaced = replaced < 0 ? 0 : replaced;
956         Array<T> result = take(from).appendAll(that);
957         from += replaced;
958         result = result.appendAll(drop(from));
959         return result;
960     }
961 
962     @Override
963     public Tuple2<Array<T>, Array<T>> partition(Predicate<? super T> predicate) {
964         Objects.requireNonNull(predicate, "predicate is null");
965         final java.util.List<T> left = new ArrayList<>(), right = new ArrayList<>();
966         for (T t : this) {
967             (predicate.test(t) ? left : right).add(t);
968         }
969         return Tuple.of(ofAll(left), ofAll(right));
970     }
971 
972     @Override
973     public Array<T> peek(Consumer<? super T> action) {
974         Objects.requireNonNull(action, "action is null");
975         if (!isEmpty()) {
976             action.accept(head());
977         }
978         return this;
979     }
980 
981     @Override
982     public Array<Array<T>> permutations() {
983         if (isEmpty()) {
984             return empty();
985         } else if (delegate.length == 1) {
986             return of(this);
987         } else {
988             Array<Array<T>> results = empty();
989             for (T t : distinct()) {
990                 for (Array<T> ts : remove(t).permutations()) {
991                     results = results.append(of(t).appendAll(ts));
992                 }
993             }
994             return results;
995         }
996     }
997 
998     @Override
999     public Array<T> prepend(T element) {
1000         return insert(0, element);
1001     }
1002 
1003     @Override
1004     public Array<T> prependAll(Iterable<? extends T> elements) {
1005         return insertAll(0, elements);
1006     }
1007 
1008     @Override
1009     public Array<T> remove(T element) {
1010         int index = -1;
1011         for (int i = 0; i < length(); i++) {
1012             final T value = get(i);
1013             if (Objects.equals(element, value)) {
1014                 index = i;
1015                 break;
1016             }
1017         }
1018         if (index < 0) {
1019             return this;
1020         } else {
1021             return removeAt(index);
1022         }
1023     }
1024 
1025     @Override
1026     public Array<T> removeFirst(Predicate<T> predicate) {
1027         Objects.requireNonNull(predicate, "predicate is null");
1028         int found = -1;
1029         for (int i = 0; i < length(); i++) {
1030             final T value = get(i);
1031             if (predicate.test(value)) {
1032                 found = i;
1033                 break;
1034             }
1035         }
1036         if (found < 0) {
1037             return this;
1038         } else {
1039             return removeAt(found);
1040         }
1041     }
1042 
1043     @Override
1044     public Array<T> removeLast(Predicate<T> predicate) {
1045         Objects.requireNonNull(predicate, "predicate is null");
1046         int found = -1;
1047         for (int i = length() - 1; i >= 0; i--) {
1048             final T value = get(i);
1049             if (predicate.test(value)) {
1050                 found = i;
1051                 break;
1052             }
1053         }
1054         if (found < 0) {
1055             return this;
1056         } else {
1057             return removeAt(found);
1058         }
1059     }
1060 
1061     @Override
1062     public Array<T> removeAt(int index) {
1063         if (index < 0) {
1064             throw new IndexOutOfBoundsException("removeAt(" + index + ")");
1065         } else if (index >= length()) {
1066             throw new IndexOutOfBoundsException("removeAt(" + index + ")");
1067         } else {
1068             final Object[] arr = new Object[length() - 1];
1069             System.arraycopy(delegate, 0, arr, 0, index);
1070             System.arraycopy(delegate, index + 1, arr, index, length() - index - 1);
1071             return wrap(arr);
1072         }
1073     }
1074 
1075     @Override
1076     public Array<T> removeAll(T element) {
1077         return io.vavr.collection.Collections.removeAll(this, element);
1078     }
1079 
1080     @Override
1081     public Array<T> removeAll(Iterable<? extends T> elements) {
1082         return io.vavr.collection.Collections.removeAll(this, elements);
1083     }
1084 
1085     @Override
1086     public Array<T> removeAll(Predicate<? super T> predicate) {
1087         return io.vavr.collection.Collections.removeAll(this, predicate);
1088     }
1089 
1090     @Override
1091     public Array<T> replace(T currentElement, T newElement) {
1092         final Object[] arr = new Object[length()];
1093         boolean found = false;
1094         for (int i = 0; i < length(); i++) {
1095             final T value = get(i);
1096             if (found) {
1097                 arr[i] = delegate[i];
1098             } else {
1099                 if (Objects.equals(currentElement, value)) {
1100                     arr[i] = newElement;
1101                     found = true;
1102                 } else {
1103                     arr[i] = delegate[i];
1104                 }
1105             }
1106         }
1107         return found ? wrap(arr) : this;
1108     }
1109 
1110     @Override
1111     public Array<T> replaceAll(T currentElement, T newElement) {
1112         final Object[] arr = new Object[length()];
1113         boolean changed = false;
1114         for (int i = 0; i < length(); i++) {
1115             final T value = get(i);
1116             if (Objects.equals(currentElement, value)) {
1117                 arr[i] = newElement;
1118                 changed = true;
1119             } else {
1120                 arr[i] = delegate[i];
1121             }
1122         }
1123         return changed ? wrap(arr) : this;
1124     }
1125 
1126     @Override
1127     public Array<T> retainAll(Iterable<? extends T> elements) {
1128         return io.vavr.collection.Collections.retainAll(this, elements);
1129     }
1130 
1131     @Override
1132     public Array<T> reverse() {
1133         if (size() <= 1) {
1134             return this;
1135         } else {
1136             final int length = delegate.length;
1137             final Object[] arr = new Object[length];
1138             for (int i = 0, j = length - 1; i < length; i++, j--) {
1139                 arr[j] = delegate[i];
1140             }
1141             return wrap(arr);
1142         }
1143     }
1144 
1145     @Override
1146     public Array<T> scan(T zero, BiFunction<? super T, ? super T, ? extends T> operation) {
1147         return scanLeft(zero, operation);
1148     }
1149 
1150     @Override
1151     public <U> Array<U> scanLeft(U zero, BiFunction<? super U, ? super T, ? extends U> operation) {
1152         return io.vavr.collection.Collections.scanLeft(this, zero, operation, Array::ofAll);
1153     }
1154 
1155     @Override
1156     public <U> Array<U> scanRight(U zero, BiFunction<? super T, ? super U, ? extends U> operation) {
1157         return io.vavr.collection.Collections.scanRight(this, zero, operation, Array::ofAll);
1158     }
1159 
1160     @Override
1161     public Array<T> shuffle() {
1162         return io.vavr.collection.Collections.shuffle(this, Array::ofAll);
1163     }
1164 
1165     @Override
1166     public Array<T> slice(int beginIndex, int endIndex) {
1167         if (beginIndex >= endIndex || beginIndex >= length() || isEmpty()) {
1168             return empty();
1169         }
1170         if (beginIndex <= 0 && endIndex >= length()) {
1171             return this;
1172         }
1173         final int index = Math.max(beginIndex, 0);
1174         final int length = Math.min(endIndex, length()) - index;
1175         final Object[] arr = new Object[length];
1176         System.arraycopy(delegate, index, arr, 0, length);
1177         return wrap(arr);
1178     }
1179 
1180     @Override
1181     public Iterator<Array<T>> slideBy(Function<? super T, ?> classifier) {
1182         return iterator().slideBy(classifier).map(Array::ofAll);
1183     }
1184 
1185     @Override
1186     public Iterator<Array<T>> sliding(int size) {
1187         return sliding(size, 1);
1188     }
1189 
1190     @Override
1191     public Iterator<Array<T>> sliding(int size, int step) {
1192         return iterator().sliding(size, step).map(Array::ofAll);
1193     }
1194 
1195     @Override
1196     public Array<T> sorted() {
1197         final Object[] arr = copyOf(delegate, delegate.length);
1198         sort(arr);
1199         return wrap(arr);
1200     }
1201 
1202     @SuppressWarnings("unchecked")
1203     @Override
1204     public Array<T> sorted(Comparator<? super T> comparator) {
1205         final Object[] arr = copyOf(delegate, delegate.length);
1206         sort(arr, (o1, o2) -> comparator.compare((T) o1, (T) o2));
1207         return wrap(arr);
1208     }
1209 
1210     @Override
1211     public <U extends Comparable<? super U>> Array<T> sortBy(Function<? super T, ? extends U> mapper) {
1212         return sortBy(U::compareTo, mapper);
1213     }
1214 
1215     @Override
1216     public <U> Array<T> sortBy(Comparator<? super U> comparator, Function<? super T, ? extends U> mapper) {
1217         final Function<? super T, ? extends U> domain = Function1.of(mapper::apply).memoized();
1218         return toJavaStream()
1219                 .sorted((e1, e2) -> comparator.compare(domain.apply(e1), domain.apply(e2)))
1220                 .collect(collector());
1221     }
1222 
1223     @Override
1224     public Tuple2<Array<T>, Array<T>> splitAt(int n) {
1225         return Tuple.of(take(n), drop(n));
1226     }
1227 
1228     @Override
1229     public Tuple2<Array<T>, Array<T>> splitAt(Predicate<? super T> predicate) {
1230         Objects.requireNonNull(predicate, "predicate is null");
1231         final Array<T> init = takeWhile(predicate.negate());
1232         return Tuple.of(init, drop(init.length()));
1233     }
1234 
1235     @Override
1236     public Tuple2<Array<T>, Array<T>> splitAtInclusive(Predicate<? super T> predicate) {
1237         Objects.requireNonNull(predicate, "predicate is null");
1238         for (int i = 0; i < delegate.length; i++) {
1239             final T value = get(i);
1240             if (predicate.test(value)) {
1241                 if (i == delegate.length - 1) {
1242                     return Tuple.of(this, empty());
1243                 } else {
1244                     return Tuple.of(take(i + 1), drop(i + 1));
1245                 }
1246             }
1247         }
1248         return Tuple.of(this, empty());
1249     }
1250 
1251     @Override
1252     public Tuple2<Array<T>, Array<T>> span(Predicate<? super T> predicate) {
1253         Objects.requireNonNull(predicate, "predicate is null");
1254         return Tuple.of(takeWhile(predicate), dropWhile(predicate));
1255     }
1256 
1257     @Override
1258     public Array<T> subSequence(int beginIndex) {
1259         if (beginIndex < 0 || beginIndex > length()) {
1260             throw new IndexOutOfBoundsException("subSequence(" + beginIndex + ")");
1261         } else {
1262             return drop(beginIndex);
1263         }
1264     }
1265 
1266     @Override
1267     public Array<T> subSequence(int beginIndex, int endIndex) {
1268         Collections.subSequenceRangeCheck(beginIndex, endIndex, length());
1269         if (beginIndex == endIndex) {
1270             return empty();
1271         } else if (beginIndex == 0 && endIndex == length()) {
1272             return this;
1273         } else {
1274             final Object[] arr = new Object[endIndex - beginIndex];
1275             System.arraycopy(delegate, beginIndex, arr, 0, arr.length);
1276             return wrap(arr);
1277         }
1278     }
1279 
1280     @Override
1281     public Array<T> tail() {
1282         if (isEmpty()) {
1283             throw new UnsupportedOperationException("tail() on empty Array");
1284         } else {
1285             final Object[] arr = new Object[delegate.length - 1];
1286             System.arraycopy(delegate, 1, arr, 0, arr.length);
1287             return wrap(arr);
1288         }
1289     }
1290 
1291     @Override
1292     public Option<Array<T>> tailOption() {
1293         return isEmpty() ? Option.none() : Option.some(tail());
1294     }
1295 
1296     @Override
1297     public Array<T> take(int n) {
1298         if (n >= length()) {
1299             return this;
1300         } else if (n <= 0) {
1301             return empty();
1302         } else {
1303             return wrap(copyOf(delegate, n));
1304         }
1305     }
1306 
1307     @Override
1308     public Array<T> takeRight(int n) {
1309         if (n >= length()) {
1310             return this;
1311         } else if (n <= 0) {
1312             return empty();
1313         } else {
1314             final Object[] arr = new Object[n];
1315             System.arraycopy(delegate, delegate.length - n, arr, 0, n);
1316             return wrap(arr);
1317         }
1318     }
1319 
1320     @Override
1321     public Array<T> takeUntil(Predicate<? super T> predicate) {
1322         Objects.requireNonNull(predicate, "predicate is null");
1323         return takeWhile(predicate.negate());
1324     }
1325 
1326     @Override
1327     public Array<T> takeWhile(Predicate<? super T> predicate) {
1328         Objects.requireNonNull(predicate, "predicate is null");
1329         for (int i = 0; i < delegate.length; i++) {
1330             final T value = get(i);
1331             if (!predicate.test(value)) {
1332                 return take(i);
1333             }
1334         }
1335         return this;
1336     }
1337 
1338     /**
1339      * Transforms this {@code Array}.
1340      *
1341      * @param f   A transformation
1342      * @param <U> Type of transformation result
1343      * @return An instance of type {@code U}
1344      * @throws NullPointerException if {@code f} is null
1345      */
1346     public <U> U transform(Function<? super Array<T>, ? extends U> f) {
1347         Objects.requireNonNull(f, "f is null");
1348         return f.apply(this);
1349     }
1350 
1351     @Override
1352     public <T1, T2> Tuple2<Array<T1>, Array<T2>> unzip(
1353             Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) {
1354         Objects.requireNonNull(unzipper, "unzipper is null");
1355         if (isEmpty()) {
1356             return Tuple.of(empty(), empty());
1357         } else {
1358             final Object[] xs = new Object[delegate.length];
1359             final Object[] ys = new Object[delegate.length];
1360             for (int i = 0; i < delegate.length; i++) {
1361                 final Tuple2<? extends T1, ? extends T2> t = unzipper.apply(get(i));
1362                 xs[i] = t._1;
1363                 ys[i] = t._2;
1364             }
1365             return Tuple.of(wrap(xs), wrap(ys));
1366         }
1367     }
1368 
1369     @Override
1370     public <T1, T2, T3> Tuple3<Array<T1>, Array<T2>, Array<T3>> unzip3(Function<? super T, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) {
1371         Objects.requireNonNull(unzipper, "unzipper is null");
1372         if (isEmpty()) {
1373             return Tuple.of(empty(), empty(), empty());
1374         } else {
1375             final Object[] xs = new Object[delegate.length];
1376             final Object[] ys = new Object[delegate.length];
1377             final Object[] zs = new Object[delegate.length];
1378             for (int i = 0; i < delegate.length; i++) {
1379                 final Tuple3<? extends T1, ? extends T2, ? extends T3> t = unzipper.apply(get(i));
1380                 xs[i] = t._1;
1381                 ys[i] = t._2;
1382                 zs[i] = t._3;
1383             }
1384             return Tuple.of(wrap(xs), wrap(ys), wrap(zs));
1385         }
1386     }
1387 
1388     @Override
1389     public Array<T> update(int index, T element) {
1390         if ((index < 0) || (index >= length())) {
1391             throw new IndexOutOfBoundsException("update(" + index + ")");
1392         } else {
1393             final Object[] arr = copyOf(delegate, delegate.length);
1394             arr[index] = element;
1395             return wrap(arr);
1396         }
1397     }
1398 
1399     @Override
1400     public Array<T> update(int index, Function<? super T, ? extends T> updater) {
1401         Objects.requireNonNull(updater, "updater is null");
1402         return update(index, updater.apply(get(index)));
1403     }
1404 
1405     @Override
1406     public <U> Array<Tuple2<T, U>> zip(Iterable<? extends U> that) {
1407         return zipWith(that, Tuple::of);
1408     }
1409 
1410     @Override
1411     public <U, R> Array<R> zipWith(Iterable<? extends U> that, BiFunction<? super T, ? super U, ? extends R> mapper) {
1412         Objects.requireNonNull(that, "that is null");
1413         Objects.requireNonNull(mapper, "mapper is null");
1414         return ofAll(iterator().zipWith(that, mapper));
1415     }
1416 
1417     @Override
1418     public <U> Array<Tuple2<T, U>> zipAll(Iterable<? extends U> that, T thisElem, U thatElem) {
1419         Objects.requireNonNull(that, "that is null");
1420         return ofAll(iterator().zipAll(that, thisElem, thatElem));
1421     }
1422 
1423     @Override
1424     public Array<Tuple2<T, Integer>> zipWithIndex() {
1425         return ofAll(iterator().zipWithIndex());
1426     }
1427 
1428     @Override
1429     public <U> Array<U> zipWithIndex(BiFunction<? super T, ? super Integer, ? extends U> mapper) {
1430         Objects.requireNonNull(mapper, "mapper is null");
1431         return ofAll(iterator().zipWithIndex(mapper));
1432     }
1433 
1434     @Override
1435     public boolean equals(Object o) {
1436         return io.vavr.collection.Collections.equals(this, o);
1437     }
1438 
1439     @Override
1440     public int hashCode() {
1441         return io.vavr.collection.Collections.hashOrdered(this);
1442     }
1443 
1444     @Override
1445     public String stringPrefix() {
1446         return "Array";
1447     }
1448 
1449     @Override
1450     public String toString() {
1451         return mkString(stringPrefix() + "(", ", ", ")");
1452     }
1453 
1454     private static <T> Object[] toArray(Iterable<T> elements) {
1455         if (elements instanceof Array) {
1456             final Array<T> array = (Array<T>) elements;
1457             return array.delegate;
1458         } else {
1459             return io.vavr.collection.Collections.withSize(elements).toArray();
1460         }
1461     }
1462 }
1463 
1464 interface ArrayModule {
1465 
1466     final class Combinations {
1467 
1468         static <T> Array<Array<T>> apply(Array<T> elements, int k) {
1469             if (k == 0) {
1470                 return Array.of(Array.empty());
1471             } else {
1472                 return elements.zipWithIndex().flatMap(
1473                         t -> apply(elements.drop(t._2 + 1), (k - 1)).map(c -> c.prepend(t._1))
1474                 );
1475             }
1476         }
1477     }
1478 }